#include "calculator.h"
#include "napi/native_api.h"
#include <string>
#include <vector>
#include <unordered_map>
#include <cmath>

#define DECLARE_NAPI_FUNCTION(name, fn) { name, nullptr, fn, nullptr, nullptr, nullptr, napi_default, nullptr }

// 全局计算器实例
static std::unique_ptr<Calculator> g_calculator = nullptr;

// 工具函数：创建字符串
static napi_value CreateString(napi_env env, const std::string& str) {
    napi_value result;
    napi_create_string_utf8(env, str.c_str(), str.length(), &result);
    return result;
}

// 工具函数：创建数字
static napi_value CreateDouble(napi_env env, double value) {
    napi_value result;
    napi_create_double(env, value, &result);
    return result;
}

// 工具函数：创建对象
static napi_value CreateObject(napi_env env) {
    napi_value result;
    napi_create_object(env, &result);
    return result;
}

// 工具函数：获取字符串参数
static std::string GetStringParam(napi_env env, napi_value value) {
    size_t len;
    napi_get_value_string_utf8(env, value, nullptr, 0, &len);
    std::string result(len, '\0');
    napi_get_value_string_utf8(env, value, &result[0], len + 1, &len);
    return result;
}

// 工具函数：获取数字参数
static double GetDoubleParam(napi_env env, napi_value value) {
    double result;
    napi_get_value_double(env, value, &result);
    return result;
}

// 基本表达式计算
static napi_value Calculate(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 1) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    std::string expression = GetStringParam(env, args[0]);
    
    try {
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        double result = g_calculator->evaluate(expression);
        return CreateString(env, std::to_string(result));
    } catch (const std::exception& e) {
        napi_throw_error(env, nullptr, e.what());
        return nullptr;
    }
}

// 复数加法
static napi_value ComplexAdd(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 4) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real1 = GetDoubleParam(env, args[0]);
        double imag1 = GetDoubleParam(env, args[1]);
        double real2 = GetDoubleParam(env, args[2]);
        double imag2 = GetDoubleParam(env, args[3]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex a(real1, imag1);
        Complex b(real2, imag2);
        Complex result = g_calculator->complexAdd(a, b);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数减法
static napi_value ComplexSubtract(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 4) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real1 = GetDoubleParam(env, args[0]);
        double imag1 = GetDoubleParam(env, args[1]);
        double real2 = GetDoubleParam(env, args[2]);
        double imag2 = GetDoubleParam(env, args[3]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex a(real1, imag1);
        Complex b(real2, imag2);
        Complex result = g_calculator->complexSubtract(a, b);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数乘法
static napi_value ComplexMultiply(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 4) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real1 = GetDoubleParam(env, args[0]);
        double imag1 = GetDoubleParam(env, args[1]);
        double real2 = GetDoubleParam(env, args[2]);
        double imag2 = GetDoubleParam(env, args[3]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex a(real1, imag1);
        Complex b(real2, imag2);
        Complex result = g_calculator->complexMultiply(a, b);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数除法
static napi_value ComplexDivide(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 4) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real1 = GetDoubleParam(env, args[0]);
        double imag1 = GetDoubleParam(env, args[1]);
        double real2 = GetDoubleParam(env, args[2]);
        double imag2 = GetDoubleParam(env, args[3]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex a(real1, imag1);
        Complex b(real2, imag2);
        Complex result = g_calculator->complexDivide(a, b);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数幂运算
static napi_value ComplexPower(napi_env env, napi_callback_info info) {
    size_t argc = 4;
    napi_value args[4];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 4) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real1 = GetDoubleParam(env, args[0]);
        double imag1 = GetDoubleParam(env, args[1]);
        double real2 = GetDoubleParam(env, args[2]);
        double imag2 = GetDoubleParam(env, args[3]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex base(real1, imag1);
        Complex exp(real2, imag2);
        Complex result = g_calculator->complexPower(base, exp);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数开方
static napi_value ComplexSqrt(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexSqrt(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数正弦 NAPI 接口
static napi_value ComplexSin(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (!g_calculator) {
        g_calculator = std::make_unique<Calculator>();
    }
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexSin(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数余弦 NAPI 接口
static napi_value ComplexCos(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (!g_calculator) {
        g_calculator = std::make_unique<Calculator>();
    }
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexCos(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数正切 NAPI 接口
static napi_value ComplexTan(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (!g_calculator) {
        g_calculator = std::make_unique<Calculator>();
    }
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexTan(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数指数 NAPI 接口
static napi_value ComplexExp(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (!g_calculator) {
        g_calculator = std::make_unique<Calculator>();
    }
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexExp(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 复数对数 NAPI 接口
static napi_value ComplexLog(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (!g_calculator) {
        g_calculator = std::make_unique<Calculator>();
    }
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    try {
        double real = GetDoubleParam(env, args[0]);
        double imag = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        Complex z(real, imag);
        Complex result = g_calculator->complexLog(z);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "real", CreateDouble(env, result.real()));
        napi_set_named_property(env, obj, "imaginary", CreateDouble(env, result.imag()));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 数值微分
static napi_value Derivative(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 2) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        std::string expression = GetStringParam(env, args[0]);
        double x = GetDoubleParam(env, args[1]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        // 创建函数对象
        auto f = [&expression](double val) -> double {
            // 这里需要一个表达式解析器来计算函数值
            // 简化实现：假设表达式是 "x^2" 形式
            if (expression == "x^2") {
                return val * val;
            } else if (expression == "x^3") {
                return val * val * val;
            } else if (expression == "sin(x)") {
                return sin(val);
            } else {
                return val; // 默认返回x
            }
        };
        
        double result = g_calculator->derivative(f, x);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "result", CreateDouble(env, result));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

// 数值积分
static napi_value Integral(napi_env env, napi_callback_info info) {
    size_t argc = 3;
    napi_value args[3];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    if (argc < 3) {
        napi_throw_error(env, nullptr, "Wrong number of arguments");
        return nullptr;
    }
    
    try {
        std::string expression = GetStringParam(env, args[0]);
        double a = GetDoubleParam(env, args[1]);
        double b = GetDoubleParam(env, args[2]);
        
        if (!g_calculator) {
            g_calculator = std::make_unique<Calculator>();
        }
        
        // 创建函数对象
        auto f = [&expression](double val) -> double {
            // 简化实现：假设表达式是 "x^2" 形式
            if (expression == "x^2") {
                return val * val;
            } else if (expression == "x^3") {
                return val * val * val;
            } else if (expression == "sin(x)") {
                return sin(val);
            } else {
                return val; // 默认返回x
            }
        };
        
        double result = g_calculator->integral(f, a, b);
        
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "result", CreateDouble(env, result));
        
        return obj;
    } catch (const std::exception& e) {
        napi_value obj = CreateObject(env);
        napi_set_named_property(env, obj, "error", CreateString(env, e.what()));
        return obj;
    }
}

static napi_value Init(napi_env env, napi_value exports) {
    // 创建计算器实例
    g_calculator = std::make_unique<Calculator>();

    // 定义导出函数
    napi_property_descriptor descriptors[] = {
        {"calculate",       nullptr, Calculate,       nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexAdd",      nullptr, ComplexAdd,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexSubtract", nullptr, ComplexSubtract, nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexMultiply", nullptr, ComplexMultiply, nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexDivide",   nullptr, ComplexDivide,   nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexPower",    nullptr, ComplexPower,    nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexSqrt",     nullptr, ComplexSqrt,     nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexSin",      nullptr, ComplexSin,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexCos",      nullptr, ComplexCos,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexTan",      nullptr, ComplexTan,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexExp",      nullptr, ComplexExp,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"complexLog",      nullptr, ComplexLog,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"derivative",      nullptr, Derivative,      nullptr, nullptr, nullptr, napi_default, nullptr },
        {"integral",        nullptr, Integral,        nullptr, nullptr, nullptr, napi_default, nullptr },
   };

    napi_define_properties(env, exports, sizeof(descriptors) / sizeof(descriptors[0]), descriptors);
    return exports;
}

// 模块定义
static napi_module calculator_module = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = nullptr,
    .reserved = {0}
};

// 模块注册
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
    napi_module_register(&calculator_module);
}